import { ForbiddenException, Injectable } from '@nestjs/common';
import { CreateRoleDto } from './dto/create-role.dto';
import { UpdateRoleDto } from './dto/update-role.dto';
import { QueryRoleDto } from './dto/query-role.dto';
import { InjectRepository, InjectEntityManager } from '@nestjs/typeorm';
import { Repository, EntityManager, In } from 'typeorm';
import { Role } from './entities/role.entity';
import { ApiTags } from '@nestjs/swagger';
import { RoleMenuService } from '../role-menu/role-menu.service';
import { RoleDeptService } from '../role-dept/role-dept.service';
import { RoleMenu } from '../role-menu/entities/role-menu.entity';
import { RoleDept } from '../role-dept/entities/role-dept.entity';
import { UserRole } from '../user-role/entities/user-role.entity';
import { Workbook } from 'exceljs';
import { Request, Response } from 'express';
import { StatusChangeDto } from 'src/common/baseDto/status-change.dto';
import { User } from '../user/entities/user.entity';

@ApiTags('角色')
@Injectable()
export class RoleService {
  constructor(
    @InjectRepository(Role) private readonly role: Repository<Role>,
    @InjectRepository(UserRole) private readonly userRole: Repository<UserRole>,
    @InjectEntityManager() private entityManager: EntityManager,
    private readonly roleMenu: RoleMenuService,
    private readonly roleDept: RoleDeptService,
  ) {}

  /**
   * 创建角色
   * @param createRoleDto
   * @returns
   */
  async create(createRoleDto: CreateRoleDto) {
    let paramsRole = createRoleDto.role;
    let menuIds = createRoleDto.menuIds;
    const role = await this.role.save(paramsRole);
    if (menuIds && menuIds.length > 0) {
      await this.createRoleMenu(menuIds, role.role_id);
    }
    return role;
  }

  /**
   * 角色列表
   * @param query
   * @returns
   */
  async findAll(query: QueryRoleDto) {
    let queryBuilder = this.role.createQueryBuilder('role');
    // 处理查询条件
    if (query.role_name) {
      queryBuilder = queryBuilder.andWhere('role.role_name Like :roleName', {
        roleName: `%${query.role_name}%`,
      });
    }
    if (query.role_key) {
      queryBuilder = queryBuilder.andWhere('role.role_key LIKE :roleKey', {
        roleKey: `%${query.role_key}%`,
      });
    }
    if (query.status) {
      queryBuilder = queryBuilder.andWhere('role.status  LIKE :status ', {
        status: `${query.status}`,
      });
    }
    if (query.begin_time && query.end_time) {
      queryBuilder = queryBuilder.andWhere(
        'role.create_time BETWEEN :beginTime AND :endTime',
        {
          beginTime: query.begin_time,
          endTime: query.end_time,
        },
      );
    }

    // 处理分页
    if (!query.pageNum || query.pageNum < 1) {
      query.pageNum = 1;
    }
    if (!query.pageSize || query.pageSize < 1) {
      query.pageSize = 10;
    }
    queryBuilder = queryBuilder
      .skip((query.pageNum - 1) * query.pageSize)
      .take(query.pageSize)
      .orderBy('role.role_sort', 'ASC');
    let total = await queryBuilder.getCount();
    let list = await queryBuilder.getMany();
    return {
      pageNum: query.pageNum,
      pageSize: query.pageSize,
      total,
      list,
    };
  }

  /**
   * 角色详情
   * @param id
   * @returns
   */
  async findOne(id: number) {
    let role = await this.role.findOne({
      where: {
        role_id: id,
      },
    });
    let roleMenus = await this.roleMenu.findAll(id);
    let roleDepts = await this.roleDept.findAll(id);
    return {
      role,
      roleMenus: roleMenus.map((item) => item.menu_id),
      roleDepts: roleDepts.map((item) => item.dept_id),
    };
  }

  /**
   * 修改角色（角色关联的菜单、部门）
   * @param role_id
   * @param updateRoleDto
   * @param req
   * @returns
   */
  async update(role_id: number, updateRoleDto: UpdateRoleDto,req:Request) {
    let paramsRole = updateRoleDto.role;
    let menuIds = updateRoleDto.menuIds;
    let deptIds = updateRoleDto.deptIds;
    let user = req.user as User;
    paramsRole.update_by = user.username
    const role = await this.role.update(role_id, paramsRole);
    if (menuIds) {
      await this.roleMenu.updateRoleMenu(menuIds, role_id);
    }
    if (deptIds) {
      await this.roleDept.updateRoleDept(deptIds, role_id);
    }
    return role;
  }

    /**
   * 更新角色状态
   * @param statusChangeDto
   * @param req
   */
    statusChange(statusChangeDto: StatusChangeDto,req:Request) {
      let user = req.user as User;
      return this.role.update(statusChangeDto.id, {
        status: statusChangeDto.status,
        update_by: user.username
      });
    }

  /**
   * 删除角色
   * @param roleIds
   * @returns
   */
  async remove(roleIds: number[]) {
    const count = await this.countUserIdByRole(roleIds);
    if (count > 0) {
      throw new ForbiddenException('该角色下存在用户，无法删除');
    }
    try {
      await this.entityManager.transaction(async (manager) => {
        await manager.delete(Role, { role_id: In(roleIds) });
        await manager.delete(RoleMenu, { role_id: In(roleIds) });
        await manager.delete(RoleDept, { role_id: In(roleIds) });
      });
    } catch (err) {
      return err;
    }
  }

  /**
   * 创建角色菜单关联
   * @param menuIds  //菜单数组
   * @param roleId   //角色ID
   */
  async createRoleMenu(menuIds: number[], roleId: number) {
    const insertRows = menuIds.map((k) => {
      return {
        role_id: roleId,
        menu_id: k,
      };
    });
    return this.roleMenu.insert(insertRows);
  }

  /**
   * 创建角色部门关联
   * @param deptIds  //部门数组
   * @param roleId   //角色ID
   */
  async createRoleDept(deptIds: number[], roleId: number) {
    const insertRows = deptIds.map((k) => {
      return {
        role_id: roleId,
        dept_id: k,
      };
    });
    return this.roleDept.insert(insertRows);
  }

  /**
   * 根据角色ID列表查找关联用户ID
   * @param ids
   */
  async countUserIdByRole(ids: number[]) {
    if (ids.some((k) => k === 1)) {
      throw new ForbiddenException('超级管理员不允许删除');
    }
    return await this.userRole.count({ where: { role_id: In(ids) } });
  }

  /**
   * 导出为表格
   * @param res
   */
  async exportToExcel(res: Response) {
    const workbook = new Workbook();
    const worksheet = workbook.addWorksheet('角色');

    worksheet.columns = [
      { header: '角色ID', key: 'role_id', width: 10 },
      { header: '角色名称', key: 'role_name', width: 10 },
      { header: '角色权限', key: 'role_key', width: 10 },
      { header: '角色排序', key: 'role_sort', width: 10 },
      { header: '角色状态', key: 'status', width: 10 },
      { header: '创建者', key: 'create_by', width: 10 },
      { header: '创建时间', key: 'create_time', width: 10 },
      { header: '更新者', key: 'update_by', width: 10 },
      { header: '更新时间', key: 'update_time', width: 10 },
      { header: '备注', key: 'remark', width: 10 },
    ];

    const data = await this.role.find();
    worksheet.addRows(data);
    res.setHeader(
      'Content-Type',
      'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    );
    let filename = encodeURIComponent('角色.xlsx')  // 这里中文需要转码
    res.setHeader('Content-Disposition', 'attachment; filename='+filename+'');
    res.setHeader('Cache-Control', 'max-age=0');
    const file = await workbook.xlsx.writeBuffer();
    res.end(file)
  }
}
